iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 2
1

本篇文章使用Unity 2019 LTS版本,畫面及API可能會有所不同。

目標

  • Unity Shader的程式碼結構
  • 幫我們的「朋友」自由的更換顏色

前置作業

第一步

首先先新增一個Shader出來。

Create -> Shader -> Unlit Shader

第二步

新增一個材質(Material)

Create -> Material

將剛的Shader附加上去在這個新的Material上去。

第三步

在場景中,創建一個新朋友,來當我們實驗對象,這邊我選了Sphere。(作者很黑,會把朋友拿去做實驗)

把剛剛材質(Material)附加到我們新朋友上,準確來說是Mesh Renderer的Materials。

開始撰寫吧!

用你最喜歡的編輯器把Shader打開後,把預設的程式碼都刪掉,貼上以下的程式碼。這樣我就完成了一個最簡單「不受光源影響,可以變更顏色」的Shader。

以下的程式碼已經在註解中給出了該片段的意思,下面我會解釋各個區塊。

// Shader的名稱
Shader "Learning/MySimpleShader"
{
    // 屬性
    Properties 
    {
        _Color ("Color", Color) = (1.0, 1.0, 1.0, 1.0)
    }

    SubShader
    {
        Pass
        {   
            // 設定名稱、繪製狀態和標籤,可選項目
            // 在這個例子中,我們不需要進行更多設置

            // 開始撰寫Shader
            CGPROGRAM

            // 宣告vertex / fragment shader的名稱
            #pragma vertex vert
            #pragma fragment frag
            
            // 使用定義在Properties區塊的屬性
            // 注意:變數必須和區塊中的屬性以及變數名稱一致
            fixed4 _Color;
            
            // 頂點 Shader
            float4 vert(float4 v : POSITION) : SV_POSITION {
                return UnityObjectToClipPos(v);
            }
            
            // 片段 Shader
            fixed4 frag() : SV_TARGET {
                return _Color;
            }
            ENDCG
            // 結束撰寫
        }
    }
    
    // 若以上兩種Shader皆無法運行,則使用這個最低階的Shader
    // 若「不留後路」,也可直接關閉該選項
    // `Fallback Off`
    Fallback "VertexLit"
}

會發現這些內容很像C語言的語法,這是Unity提供給自家Shader的說明性語言,ShaderLab。

結構

最外層

我們往後寫的Shader都是包在這層大括號裡面,第二行的字串代表這個Shader叫做甚麼名字,以及在利用下拉選單選擇Shader時,會放在哪一層資料夾裡面。

Properties

該區塊定義變數會顯示在被附加的材質(Material)上,我們的Shader若要使用這個屬性,還要再CGPROGRAM/ENDCG中,宣告與其屬性相同的變數。

Unity有提供以下的屬性供開發者使用。

Properties
{
    _Int ("Integer", Int) = 10
    _Float ("Float", Float) = 3.14
    _Range ("Range", Range(-1.0, 1.0)) = 0.0
    _Color ("Color", Color) = (1.0, 1.0, 1.0, 1.0)
    _Vector ("Vector", Vector) = (1.0, 0.6, 7.5, 1.0)
    _2D ("Texture2D", 2D) = ""{}
    _Cube ("Texture Cube", Cube) = "white"{}
    _3D ("Texture 3D", 3D) = "black"{}
}

讀者可能發現在Shader裡使用的變數是fixed4型別。
Unity Shader對於浮點數的精度有3種,float為最高,依序下去為half跟fixed。對於何時去選用哪一種,官方文件有給出建議,並不是一定的。

SubShader

一款遊戲通常不會只發售一個平台,所以在Shader的撰寫上,會因應多個平台有不同的SubShader。

注意一個Unity Shader至少需要一個SubShader。

Pass

一個Pass就是一次完整的繪製流程
Pass和SubShader一樣,可以在一個SubShader中,定義多個Pass,遊戲中許多絢麗的效果是需要多Pass處理的,同時使用過多的Pass會造成效能降低。

CGPRGRAM/ENDCG

我們主要功能的程式碼是寫在這個區塊裡面的,會發現這些函式與C語言非常相近,設置看的出來有些式macro。

先來看看第21行和第22行

#pragma vertex vert
#pragma fragment frag

表示我們要將我們的vertex shader和fragment shader稱做甚麼,不知道甚麼是vertex shader或是fragment shader沒關係,我們很快就會提到他,在這裡,我們只需要知道:

  1. vertex shader處理模型的頂點
  2. fragment shader處理像素的式怎麼畫到螢幕上的
  3. 上面所提的Pass,基本上就是通過這兩個function,將圖形處理後的結果

上面的範例,vertex shader只有一句:

return UnityObjectToClipPos(v);

意思是將物件的頂點從模型空間經過線性轉換至裁剪空間,這個函式是Unity提供的內建函式,更多的資訊可以參見官方文件

在fragment shader中,直接讓我們要輸出的像素塗上我們所選的顏色:

return _Color

發現到fragment shader的函式後面還有一個SV_TARGETSV表示system,是所謂的「語意」,原本來自於HLSL,用途在於告訴編譯器,這個變數是拿來做甚麼用的,往後我們會看到像是POSITION表示頂點的座標;TEXCOORD0表示第一組紋理(Texture)座標等等...

完成!

現在我們可以利用這編輯器裡的Color屬性,自由的幫「朋友」變換顏色了。

Reference


上一篇
你好,初次見面
下一篇
甚麼是Shader?
系列文
初見Unity Shader30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言